﻿using Engine;
using Engine.Graphics;
using Scenario_Editor.Controls;
using Scenario_Editor.Tools;
using Scenario_Editor.Windows;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using Tools;

namespace Scenario_Editor.TerrainTool
{
    public partial class TerrainMaterialBrush : UserControl
    {
        #region Private Fields

        private MaterialAssignWindows materialAssignWindow;
        private MaterialManager materialManager;
        private Terrain terrain;

        #endregion Private Fields

        #region Public Constructors

        public TerrainMaterialBrush()
        {
            InitializeComponent();
            this.materialAssignWindow = new MaterialAssignWindows();
            this.toolTip_SlopeVertexColor.SetToolTip(this.numericUpDown_PaintBlendColorMax,
                "Here you can set the maximal angle where the Vertexcolor could be painted.\n" +
                "Set it to \"90\" if you want to paint the complete terrain. \n"
                + "Set it to eg \"15\" to paint only flat terrains with a steep of maximum angle of 15 degrees.");

            this.toolTip_SlopeVertexColor.SetToolTip(this.numericUpDown_PaintBlendColorMin,
                "Here you can set the minimal angle where the Vertexcolor could be painted.\n" +
                "Set it to \"0\" if you want paint flat horizontal surface. \n"
                + "Set it to eg \"45\" to paint only steep terrains. ");
        }

        #endregion Public Constructors

        #region Internal Properties

        internal int Material
        {
            get
            {
                return this.materialManager.GetMaterialID(this.CurrentTerrainMaterial.GetMaterial());
            }
        }

        internal Terrain Terrain
        {
            get { return terrain; }
            set { terrain = value; }
        }

        #endregion Internal Properties

        #region Public Methods

        public void MaterialManagerChanged(object sender, EventArgs e)
        {
            Debug.WriteLine("new MaterialManager for TerrainControl!");
            this.materialManager = (MaterialManager)sender;
            this.materialAssignWindow.SetMaterialManager(this.materialManager);
            this.CurrentTerrainMaterial.SetDevice(this.materialManager);
            // Get the standart Material
            int materialID = materialManager.GetMaterialID(this.CurrentTerrainMaterial.GetMaterial());

            int number = 0;
            textureListBox.Items.Clear();
            foreach (string file in materialManager.TextureNames)
            {
                try
                {
                    textureListBox.Items.Add(System.IO.Path.GetFileName(file));
                    number++;
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.ToString());
                    MessageBox.Show("Error: " + file);
                }
            }

            if (textureListBox.Items.Count > 0)
                textureListBox.SelectedIndex = 0;
        }

        #endregion Public Methods

        #region Internal Methods

        internal void OnTerrainChanged(object sender, EventArgs e)
        {
            this.terrain = (Terrain)sender;
        }

        // Internal Methods (2) 
        internal void UseTool(Vector3 positionOnTerrain, Engine.Engine engine, CameraControl cameraControl, bool cursorInWorldSpace, OptionDialog oDialog, FpsCounter fpsCounter, RoadV2 roadBuilder, ObjectPlacerControl objectPlacer)
        {
            var mouse = engine.Mouse;
            var keyboard = engine.Keyboard;

            Terrain.cursor.Disable = !cursorInWorldSpace;
            Update_terrain_painting(engine, oDialog, cursorInWorldSpace, objectPlacer);
            Ray ray = new Ray(new Vector3(positionOnTerrain.X, positionOnTerrain.Y + 100, positionOnTerrain.Z), Vector3.Down * 100);
            var coordinate = terrain.GetCellCoordinate(positionOnTerrain);
            float angle;
            if (Terrain.GetNormalFromCell(coordinate.X, coordinate.Y, ray, true, false, out angle))
            {
                SetSlopeUnderCursorText(angle);
            }
            else
                SetSlopeUnderCursorText(0);
        }

        #endregion Internal Methods

        #region Private Methods

        private void button2_Click(object sender, EventArgs e)
        {
            this.textBox_TextureSearchText.Text = string.Empty;
        }

        private void numericUpDown_PaintBlendColor_ValueChanged(object sender, EventArgs e)
        {
            if (sender == this.numericUpDown_PaintBlendColorMin)
                if (this.numericUpDown_PaintBlendColorMin.Value > this.numericUpDown_PaintBlendColorMax.Value)
                    this.numericUpDown_PaintBlendColorMax.Value = this.numericUpDown_PaintBlendColorMin.Value;
        }

        private void searchTextBox_TextChanged(object sender, EventArgs e)
        {
            this.textureListBox.Items.Clear();
            string searchString = this.textBox_TextureSearchText.Text.ToUpper();
            this.textureListBox.BeginUpdate();
            for (int i = 0; i < this.materialManager.TextureNames.Count; i++)
            {
                if (searchString == string.Empty || this.materialManager.TextureNames[i].ToUpper().Contains(searchString))
                    this.textureListBox.Items.Add(this.materialManager.TextureNames[i]);
            }
            this.textureListBox.EndUpdate();

            // shows the info label of searchbox.
            this.label_InfoTextTextureFilter.Visible = (searchString == string.Empty) ? true : false;
        }

        private void SetSlopeUnderCursorText(float value)
        {
            this.label_SlopeValue.Text = value.ToString("##.#°");
        }

        private void textureListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.CurrentTerrainMaterial.SetTexture(this.materialManager.GetTextureID((string)textureListBox.SelectedItem));
        }

        private void Update_terrain_painting(Engine.Engine mdxPanel, OptionDialog oDialog, bool mouseInWorldSpace, ObjectPlacerControl sceneryObjectManager)
        {
            var mouse = mdxPanel.Mouse;
            var keyboard = mdxPanel.Keyboard;

            // Mouse Events
            Vector3 position = Terrain.GetPositionOnTerrain(mdxPanel.Grafic.VNear, mdxPanel.Grafic.VFar);
            // Mouse Events
            if (position != Vector3.Zero)
            {
                Terrain.UpdateCursor(position, (float)this.trackBar_sizeTextureBrush.Value, System.Drawing.Color.Red);
            }

            if (mouseInWorldSpace)
            {
                if (false != mouse.ButtonL)
                {
                    if (checkBox_GetTextureFromTerrain.Checked == true)
                    {
                        // Gets the material from the cell.
                        Vector3 intersectionObjects;
                        int materialIdObjects;
                        int materialIdTerrain = Terrain.GetMaterialID(position);
                        sceneryObjectManager.objectManager.IntersectObject(mdxPanel.Grafic.VNear, mdxPanel.Grafic.VFar, oDialog.Viewdistance, out materialIdObjects, out intersectionObjects);

                        this.materialAssignWindow.SetCurrentMaterial(this.CurrentTerrainMaterial.GetMaterial());

                        if (materialIdTerrain > -1 || materialIdObjects > -1)
                        {
                            if (intersectionObjects != Vector3.Zero
                                && GeoMath.DistanceBtw2Points(mdxPanel.Grafic.VNear, intersectionObjects) < GeoMath.DistanceBtw2Points(mdxPanel.Grafic.VNear, position) + 1000.0f)
                            {
                                this.materialAssignWindow.SetPickedupMateiral(this.materialManager.GetMaterial(materialIdObjects));
                            }
                            else
                            {
                                this.materialAssignWindow.SetPickedupMateiral(this.materialManager.GetMaterial(materialIdTerrain));
                            }

                            if (this.materialAssignWindow.ShowDialog() == DialogResult.OK)
                            {
                                this.CurrentTerrainMaterial.SetMaterial(this.materialAssignWindow.GetNewMaterial(), null);
                            }
                            return;
                        }
                    }

                    if (position != Vector3.Zero)
                    {
                        // Get The cells which should painted
                        List<System.Drawing.Point> cellsWhichWhichShouldPainted = Terrain.GetCellsUnderCursor(position, trackBar_sizeTextureBrush.Value + (decimal)(terrain.SECTORSIZE1 / terrain.numberOfCellsPerSector));

                        //Paint Vertex Color
                        if ((this.CurrentTerrainMaterial.PaintMode1 & MaterialPainter.PaintMode.PaintVertexColor) == MaterialPainter.PaintMode.PaintVertexColor)
                        {
                            Terrain.PaintVertexColor(position, cellsWhichWhichShouldPainted, this.CurrentTerrainMaterial.VertexColor,
                               Math.Max((decimal)(terrain.SECTORSIZE1 / terrain.numberOfCellsPerSector / 2.0f), trackBar_sizeTextureBrush.Value - (decimal)((float)trackBar_sizeTextureBrush.Value + terrain.SECTORSIZE1 / terrain.numberOfCellsPerSector) / 10),
                                (float)this.numericUpDown_PaintBlendColorMin.Value, (float)this.numericUpDown_PaintBlendColorMax.Value);
                        }
                        //Paint Material
                        if ((this.CurrentTerrainMaterial.PaintMode1 & MaterialPainter.PaintMode.PaintMaterial) == MaterialPainter.PaintMode.PaintMaterial)
                        {
                            Terrain.PaintMaterialOnTerrain(position, cellsWhichWhichShouldPainted, trackBar_sizeTextureBrush.Value, this.materialManager.GetMaterialID(this.CurrentTerrainMaterial.GetMaterial()), oDialog.Viewdistance);
                        }
                        // Smooth VertecColor
                        if ((this.CurrentTerrainMaterial.PaintMode1 & MaterialPainter.PaintMode.SmoothVertexColor) == MaterialPainter.PaintMode.SmoothVertexColor)
                        {
                            Terrain.SmoothVertexColor(position, cellsWhichWhichShouldPainted, (int)((float)trackBar_sizeTextureBrush.Value + terrain.SECTORSIZE1 / terrain.numberOfCellsPerSector), 10);
                        }
                        // Lighten Up VertecColor
                        if ((this.CurrentTerrainMaterial.PaintMode1 & MaterialPainter.PaintMode.LightenVertexColor) == MaterialPainter.PaintMode.LightenVertexColor)
                        {
                            Terrain.LightenVertexColor(position, cellsWhichWhichShouldPainted, trackBar_sizeTextureBrush.Value);
                        }
                        // Darken VertecColor
                        if ((this.CurrentTerrainMaterial.PaintMode1 & MaterialPainter.PaintMode.DarkenVertexColor) == MaterialPainter.PaintMode.DarkenVertexColor)
                        {
                            Terrain.DarkenVertexColor(position, cellsWhichWhichShouldPainted, trackBar_sizeTextureBrush.Value);
                        }
                        Terrain.UpdateTheCells(cellsWhichWhichShouldPainted);

                        //Terrain.UpdateChangedTerrain(null);
                    }
                }
                else
                {
                    if (mouse.ButtonLreleased)
                    {
                        checkBox_GetTextureFromTerrain.Checked = false;
                    }
                }

                if (mouse.ButtonR)// If right Mouse-Button is pressed
                {
                    mdxPanel.Camera.MoveUpDown(mouse.AxisY);
                    mdxPanel.Camera.MoveXY(-mouse.AxisX, 0.0f);
                }
                if (mouse.ButtonM)// If middle Mouse-Button is pressed
                {
                    mdxPanel.Camera.RotateTargetAroundCamera(-mouse.AxisX, -mouse.AxisY);
                }
                if (mouse.AxisZ != 0)// ZOOM in  and out
                {
                    mdxPanel.Camera.MoveForward(mouse.AxisZ);
                }

                if (mouse.ButtonLreleased) // for undoing
                    this.terrain.NextUndo();
            }
        }

        #endregion Private Methods
    }
}